const std = @import("std");
const Allocator = std.mem.Allocator;

/// 消息类型
pub const Message = union(enum) {
    stop,
    custom: []const u8,
};

/// Actor 状态
pub const ActorState = enum {
    idle,
    running,
    stopped,
};

/// Actor 接口
pub fn Actor(comptime StateType: type, comptime MessageType: type) type {
    return struct {
        const Self = @This();
        
        allocator: Allocator,
        arena: std.heap.ArenaAllocator,
        state: StateType,
        mailbox: std.ArrayList(MessageType),
        actor_state: ActorState,
        thread: ?std.Thread,
        mutex: std.Thread.Mutex,
        
        /// 创建新的 Actor
        pub fn init(parent_alloc: Allocator, initial_state: StateType) !*Self {
            const self = try parent_alloc.create(Self);
            
            // 每个 Actor 有独立的 Arena 分配器
            self.arena = std.heap.ArenaAllocator.init(parent_alloc);
            self.allocator = self.arena.allocator();
            
            self.state = initial_state;
            self.mailbox = std.ArrayList(MessageType).init(self.allocator);
            self.actor_state = .idle;
            self.thread = null;
            self.mutex = .{};
            
            return self;
        }
        
        /// 销毁 Actor
        pub fn deinit(self: *Self, parent_alloc: Allocator) void {
            self.stop();
            self.mailbox.deinit();
            self.arena.deinit();
            parent_alloc.destroy(self);
        }
        
        /// 发送消息到 Actor
        pub fn send(self: *Self, msg: MessageType) !void {
            self.mutex.lock();
            defer self.mutex.unlock();
            
            try self.mailbox.append(msg);
        }
        
        /// 启动 Actor
        pub fn start(self: *Self, handler: *const fn(*Self, MessageType) anyerror!void) !void {
            if (self.actor_state != .idle) return error.AlreadyRunning;
            
            self.actor_state = .running;
            self.thread = try std.Thread.spawn(.{}, runLoop, .{self, handler});
        }
        
        /// Actor 运行循环
        fn runLoop(self: *Self, handler: *const fn(*Self, MessageType) anyerror!void) void {
            while (self.actor_state == .running) {
                self.mutex.lock();
                
                if (self.mailbox.items.len > 0) {
                    const msg = self.mailbox.orderedRemove(0);
                    self.mutex.unlock();
                    
                    handler(self, msg) catch |err| {
                        std.debug.print("Actor handler error: {}\n", .{err});
                    };
                } else {
                    self.mutex.unlock();
                    std.time.sleep(1_000_000); // 1ms
                }
            }
        }
        
        /// 停止 Actor
        pub fn stop(self: *Self) void {
            if (self.actor_state != .running) return;
            
            self.actor_state = .stopped;
            if (self.thread) |thread| {
                thread.join();
                self.thread = null;
            }
        }
    };
}

/// Actor 系统 - 管理多个 Actor
pub const ActorSystem = struct {
    allocator: Allocator,
    
    pub fn init(allocator: Allocator) ActorSystem {
        return .{ .allocator = allocator };
    }
    
    /// 创建新的 Actor
    pub fn spawn(
        self: *ActorSystem,
        comptime StateType: type,
        comptime MessageType: type,
        initial_state: StateType,
    ) !*Actor(StateType, MessageType) {
        return try Actor(StateType, MessageType).init(self.allocator, initial_state);
    }
};

test "actor creation and messaging" {
    const testing = std.testing;
    
    const CounterMsg = union(enum) {
        increment,
        get_value: *u32,
    };
    
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    
    const alloc = gpa.allocator();
    
    var system = ActorSystem.init(alloc);
    var counter = try system.spawn(u32, CounterMsg, 0);
    defer counter.deinit(alloc);
    
    try testing.expect(counter.state == 0);
}
